﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using Microsoft.Kinect;
using System.Windows.Markup;
using System.IO;
using System.Xml;
using System.Timers;
using System.Windows.Threading;
using System.ComponentModel;
using Kinect.Gestures;
using System.Threading;
using KinectGestureRecognition.Interfaces;

namespace KinectGestureRecognition
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged, IUseGestures
    {
        #region INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IUseGestures implemetation
        private Border _focusedBorder;
        private DispatcherTimer _dispatcherMouseClickTimer = new DispatcherTimer();

        void initialIUseGestures()
        {
            _dispatcherMouseClickTimer.Interval = TimeSpan.FromMilliseconds(1300);
            _dispatcherMouseClickTimer.Tick += new EventHandler(_dispatcherMouseClickTimer_Tick);
        }

        void _dispatcherMouseClickTimer_Tick(object sender, EventArgs e)
        {

            // Simulate Mouse Click Action
            this._focusedBorder.Background = System.Windows.Media.Brushes.Green;
            _dispatcherMouseClickTimer.Stop();
        }

        public void borderIN(object sender, MouseEventArgs e)
        {
            Debug.WriteLine("Border IN");
            this._focusedBorder = ((Border)sender);
            this._focusedBorder.BorderBrush = System.Windows.Media.Brushes.Green;
            // Activate Mouse Click Timer
            this.MouseClickStart();
        }

        public void borderOUT(object sender, MouseEventArgs e)
        {
            Debug.WriteLine("Border Out");
            this._focusedBorder = ((Border)sender);
            this._focusedBorder.BorderBrush = System.Windows.Media.Brushes.White;
            this._focusedBorder.Background = System.Windows.Media.Brushes.White;
            this.MouseClickAbort();
        }

        public void MouseClickAbort()
        {
            this._dispatcherMouseClickTimer.Stop();
        }

        public void MouseClickStart()
        {
            this._dispatcherMouseClickTimer.Start();
        }
        #endregion

        #region members
        KinectSensorModul ksm;
        Interfaces.GestureDetectionStrategy gds;
        private DispatcherTimer _dispatcherTimer = new DispatcherTimer();
        Thread newWindowThread;
        #endregion

        #region constructors
        public MainWindow()
        {
            this.DataContext = this;
            InitializeComponent();
            // initialize the gesture recognizer
            gds = new GestureDetection.WaveGesture();
            ksm = KinectSensorModul.Instance;
            SubscribeEvents();
            _dispatcherTimer.Interval = TimeSpan.FromMilliseconds(1300);
            _dispatcherTimer.Tick += new EventHandler(delegate(object s, EventArgs a)
            {
               //this.GuiTextMessageLabel = "";
                this.ellipseGestureDetected.Fill = Brushes.Red;
                _dispatcherTimer.Stop();
            });

            // Gui Markup Timer
            initialIUseGestures();
            checkBoxColorStreamSetting.IsChecked = true;
        }   
        #endregion

        #region Properties

        private String _GuiTextMessageLabel;
        public String GuiTextMessageLabel
        {

            get
            {
                return this._GuiTextMessageLabel;
            }
            set
            {
                _GuiTextMessageLabel = value;
                if (this.PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("GuiTextMessageLabel"));
                }
               // _dispatcherTimer.Start();
            }
        }
          #region Stream Settings Properties 
          private bool _streamSettingColor;
          public bool StreamSettingColor
        {
            get
            {
                return this._streamSettingColor;
            }
            set
            {
                if (this._streamSettingColor != value)
                {
                    this._streamSettingColor = value;
                    if (value)
                    {
                        Debug.WriteLine("ColorStream on");
                        this.imageColor.Source = ksm.ColorStreamImageProp;
                    }
                    else if (!value)
                    {
                        Debug.WriteLine("ColorStream off");       
                        imageColor.Source = null;
                    }

                    if (this.PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("StreamSettingColorChanged"));
                    }
                }
            }
        }
       
          private bool _streamSettingDepth;
          public bool StreamSettingDepth
        {
            get
            {
                return this._streamSettingDepth;
            }
            set
            {
                if (this._streamSettingDepth != value)
                {
                    this._streamSettingDepth = value;
                    if (value)
                    {
                        Debug.WriteLine("DepthStream on");
                        //imageDepth.Source = ksm.DepthStreamImageProp;
                       // ksm.EnableDepthStream = true;
                        //ksm.OnDepthStreamReadyEvent += new KinectSensorModul.DepthStreamReadyEvent(ksm_OnDepthFrameReadyEvent);
                    }
                    else if (!value)
                    {
                        Debug.WriteLine("DepthStream off");
                       // ksm.EnableDepthStream = false;
                        //ksm.OnDepthStreamReadyEvent -= new KinectSensorModul.DepthStreamReadyEvent(ksm_OnDepthFrameReadyEvent);
                        imageDepth.Source = null;
                    }

                    if (this.PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("StreamSettingColorChanged"));
                    }
                }
            }
        }

          private bool _streamSettingSkeleton;
          public bool StreamSettingSkeleton
        {
            get
            {
                return this._streamSettingSkeleton;
            }
            set
            {
                if (this._streamSettingSkeleton != value)
                {
                    this._streamSettingSkeleton = value;
                    if (value)
                    {
                        Debug.WriteLine("SkeletonStream on");
                        ksm.OnSkeletonFrameReadyEvent += new KinectSensorModul.SkeletonFrameReadyEvent(ksm_OnSkeletonFrameReadyEvent);
                    }
                    else if (!value)
                    {
                        Debug.WriteLine("SkeletonStream off");
                        ksm.OnSkeletonFrameReadyEvent -= new KinectSensorModul.SkeletonFrameReadyEvent(ksm_OnSkeletonFrameReadyEvent);
                        imageSkeleton.Source = null;
                    }

                    if (this.PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("SkeletonSettingColorChanged"));
                    }
                }
            }
        }
        
          private bool _streamSettingGesture;
          public bool StreamSettingGesture
        {
            get
            {
                return this._streamSettingGesture;
            }
            set
            {
                if (this._streamSettingGesture != value)
                {
                    this._streamSettingGesture = value;
                    if (value)
                    {
                        Debug.WriteLine("GestureStream on");
                        ksm.EnableGestureController = true;
                    }
                    else if (!value)
                    {
                        Debug.WriteLine("GestureStream off");
                        ksm.EnableGestureController = false;
                    }

                    if (this.PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("GestureSettingColorChanged"));
                    }
                }
            }
        }

          private bool _mouseController;
          public bool EnableMouseController
          {
              get
              {
                  return this._mouseController;
              }
              set
              {
                  if (this._mouseController != value)
                  {
                      this._mouseController = value;
                      if (value)
                      {
                          Debug.WriteLine("MouseController on");
                          this.ksm.EnableMouseController = true;
                      }
                      else if (!value)
                      {
                          Debug.WriteLine("MouseController off");
                          this.ksm.EnableMouseController = false;
                      }

                      if (this.PropertyChanged != null)
                      {
                          PropertyChanged(this, new PropertyChangedEventArgs("MouseControllerChanged"));
                      }
                  }
              }
          }
          #endregion
        #endregion

        #region events

        private void SubscribeEvents()
        {
            ksm.OnGestureDetectionEvent += new KinectSensorModul.GestureDetectionEvent(ksm_OnGestureDetectionEvent);
            ksm.OnSkeletonTrackedStateReadyEvent += new KinectSensorModul.SkeletonTrackedStateChangedEvent(ksm_OnSkeletonTrackedStateReadyEvent);
            ksm.OnLeftMouseStateChangedEvent += new KinectSensorModul.LeftMouseStateChangedEvent(ksm_OnLeftMouseStateChangedEvent);
        }

        void ksm_OnLeftMouseStateChangedEvent(object sender, bool LeftMouseDownState)
        {
            Debug.WriteLine("Left Mouse Down State: " + LeftMouseDownState);
            if (LeftMouseDownState)
            {
                this.ellipseLeftMouseDown.Fill = Brushes.GreenYellow;
            }
            else
            {
                this.ellipseLeftMouseDown.Fill = Brushes.Red;
            }
        }

        void ksm_OnSkeletonTrackedStateReadyEvent(object sender, bool trackedState)
        {
            Debug.WriteLine("Skeleton Tracked State: " + trackedState);
            if (trackedState)
            {
                this.ellipseSkeletonTrackedState.Fill = Brushes.GreenYellow;
            }
            else
            {
                this.ellipseSkeletonTrackedState.Fill = Brushes.Red;
            }
        }

        void ksm_OnGestureDetectionEvent(object sender, string GestureType)
        {
            Debug.WriteLine(" ---- Gesture Detected:  " + GestureType);
            GuiTextMessageLabel = GestureType;
            this.ellipseGestureDetected.Fill = Brushes.GreenYellow;
            _dispatcherTimer.Start();
        }

        void ksm_OnSkeletonFrameReadyEvent(object sender, ImageSource skeletonFrame)
        {
            imageSkeleton.Source = skeletonFrame;           
        }

        void ksm_OnDepthFrameReadyEvent(object sender, BitmapSource colorFrame)
        {
            imageDepth.Source = colorFrame;
        }
        #endregion

        #region help functions

        public void StartObjectDetectionWindowParallel()
        {


            Thread thread = new Thread(() =>
            {
                //private ObjectDetection.ObjectDetectorWindow ObjectDetectionWindow;
                ObjectDetection.ObjectDetectorWindow ObjectDetectionWindow = new ObjectDetection.ObjectDetectorWindow();
                ObjectDetectionWindow.Show();

                System.Windows.Threading.Dispatcher.Run();
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();

        }

        private void NewWindowHandler(object sender, RoutedEventArgs e)
        {
            newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.IsBackground = true;
            newWindowThread.Start();
        }

        private void ThreadStartingPoint()
        {
            ObjectDetection.ObjectDetectorWindow tempWindow = new ObjectDetection.ObjectDetectorWindow();
            tempWindow.Show();
            System.Windows.Threading.Dispatcher.Run();
        }

        public static UIElement DeepCopy(UIElement element)
        {
            if (element != null)
            {
                var xaml = XamlWriter.Save(element);

                var xamlString = new StringReader(xaml);

                var xmlTextReader = new XmlTextReader(xamlString);

                var deepCopyObject = (UIElement)XamlReader.Load(xmlTextReader);

                return deepCopyObject;
            }

            return null;

        }


        private Canvas CopyCanvas(Canvas inputCanvas)
        {

            if (inputCanvas != null)
            {
                var outputCanvas = new Canvas();

                foreach (UIElement child in inputCanvas.Children)
                {
                    outputCanvas.Children.Add(DeepCopy(child));
                }

                return outputCanvas;
            }

            return null;
        }

        private UIElement Clone(Object element) {
    string xaml = XamlWriter.Save(element);
    return (UIElement) XamlReader.Load(new XmlTextReader(new         StringReader(xaml)));

        }
        #endregion


        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

        }

        
    }
}
